package org.scisaga.tetra.core;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.matheclipse.basic.Config;
import org.matheclipse.core.eval.EvalEngine;
import org.matheclipse.core.eval.EvalUtilities;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.form.output.OutputFormFactory;
import org.matheclipse.core.form.output.StringBufferWriter;
import org.matheclipse.core.interfaces.IExpr;

//import edu.jas.kern.ComputerThreads;

public class EvalJ implements Eval{
	EvalEngine evalEngine;
	EvalUtilities util;
	
	StringBufferWriter buf;
	
	ArrayList<String> evalList;
	HashMap<String, String> input;
	
	public static Messager mgr;
	
	public EvalJ(ArrayList<String> eval){

		F.initSymbols(null);
		Config.SERVER_MODE = true;
		
		evalEngine = new EvalEngine();
		util = new EvalUtilities();
		evalList = eval;
		input = new HashMap<String, String>();
	}
	
	public EvalJ(String eval) {

		F.initSymbols(null);
		Config.SERVER_MODE = true;
		
		evalEngine = new EvalEngine();
		util = new EvalUtilities();
		
		input = new HashMap<String, String>();
		evalList = new ArrayList<String>();
		JSONObject evalJson = null;
		try {
			evalJson = new JSONObject(eval);
			JSONArray evalArray = evalJson.getJSONArray("eval");
			for (int i = 0; i < evalArray.length(); i++)
				evalList.add(evalArray.getString(i));

		} catch (JSONException e) {

			e.printStackTrace();
			log("Eval() -> Input JSON String is invalid");
		}
	}
	
	@SuppressWarnings("unchecked")
	public void load(String in) {
		JSONObject inputJson = null;
		try {
			inputJson = new JSONObject(in);
			for (Iterator<String> iter = inputJson.keys(); iter.hasNext();) {
				String key = iter.next();
				input.put(key, inputJson.getString(key));
			}
			this.load(input);
		} catch (JSONException e) {
			log("Eval::load() -> Input JSON String is invalid");
		}
	}
	
	public void load(HashMap<String, String> in){
		input = in;
		
		try {
			buf = new StringBufferWriter();
			EvalEngine.getVariableMap().clear();
			
			for (String key : input.keySet()) {
				evalEngine.evaluate(key + "=" + input.get(key));
			}
			for (String eval : evalList) {
				evalEngine.evaluate(eval);
			}
			
		} catch (Exception e) {
			log(evalList);
			log(input);
			e.printStackTrace();
		}
		
	}
	
	public HashMap<String,String> genHash(ArrayList<String> varOut) {
		HashMap<String,String> output = new HashMap<String,String>();
		try {
			for (Iterator<String> iter = varOut.iterator(); iter.hasNext();) {
				String var = iter.next();
				buf = new StringBufferWriter();
				IExpr temp = evalEngine.evaluate(var);
				OutputFormFactory.get().convert(buf, temp);
				output.put(var,buf.toString());
				evalEngine.reset();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			//ComputerThreads.terminate();
		}
		return output;
	}
	
	public String gen(String varOutString) {
		ArrayList<String> varOut = new ArrayList<String>();
		JSONObject varOutJson = null;
		JSONObject OutputJson = null;
		
		try {
			varOutJson = new JSONObject(varOutString);
			JSONArray evalArray = varOutJson.getJSONArray("varOut");
			for (int i = 0; i < evalArray.length(); i++)
				varOut.add(evalArray.getString(i));
			
			HashMap<String,String> output = this.genHash(varOut);
			OutputJson = new JSONObject(output);
			
		} catch (JSONException e) {
			log("Eval::gen() -> JSONException");
		}
		
		return OutputJson.toString();
	}
	
	protected static void log(String s) {
		if(mgr != null){
			mgr.computeNode.log("Process :: " + s);
		} else System.out.println("Process :: " + s);
	}
	
	private static void log(HashMap<String,String> token){
		if(token.isEmpty()) log("No Available Tokens");
		String output = "";
		for(String s : token.keySet()){
			output += "["+s+","+token.get(s)+"]";
		}
		log(output);
	}
	
	private static void log(ArrayList<String> token){
		String output = "";
		for(String s : token){
			output += "["+s+"]";
		}
		System.out.println(output);
	}
	
	public static void main(String[] args) {
		F.initSymbols(null);
		Config.SERVER_MODE = true;
		
		new EvalJTest("AAA","{\"eval\":[\"If[$x==10,$z=2;$y=$z+1,2,3]\"]}").start();
		//new EvalJTest("BBB","{\"eval\":[\"$y=$x\"]}").start();
		//new EvalJTest("CCC","{\"eval\":[\"$y=$x\"]}").start();
	}
}

class EvalJTest extends Thread {
	String name;
	String rules;
	String result="";
	
	EvalJTest(String s,String r){
		name = s;
		rules = r;
	}
	
	public void run(){
		EvalJ p = new EvalJ(rules);
		
		for(int i=0;i<100;i++){
			p.load("{\"$x\":\""+i+"\"}");		// load the input variables
			JSONObject r;
			try {
				r = new JSONObject(p.gen("{\"varOut\":[\"$y\"]}"));
				result += r.getString("$y") + ",";
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
		
		System.out.println(name+":"+result);
	}
}